
//When Branch Prediction Failed , it will flush the load/store operations in error execution path
module frv_lsu_top (
    input                       clk             ,
    input                       rst_n           ,
    input                       pd_rst          ,
    //LSU Control
    input                       lsu_req         ,
    output                      lsu_ready       ,
    input                       lsu_ctrl_unsign ,
    input                       lsu_ctrl_load   ,
    input                       lsu_ctrl_store  ,
    input                       lsu_ctrl_word   ,
    input                       lsu_ctrl_half   ,
    input                       lsu_ctrl_byte   ,
    input [5:0]     lsu_inst_id     , 
    input                       lsu_flush       ,
    input [5:0]     lsu_flush_id    ,
    
    input                       lsu_stor_retire ,
    input [5:0]     lsu_stor_rid    ,

    //LSU Operation Number
    input [31:0]                lsu_op1_val     ,
    input [31:0]                lsu_op2_val     ,    
    input [31:0]                lsu_store_data  ,
    //LSU Response Interface
    output [5:0]    lsu_resp_inst_id,
    output                      lsu_resp_vld    ,
    output                      lsu_resp_rd_vld ,
    output [5:0]                lsu_resp_rd_ind ,
    output [31:0]               lsu_resp_rd_val ,//rd value    
    output                      lsu_exp_vld     ,//ignore it when exception feature is not implemented
    //DMem Control
    output                      dmem_req        ,
    output                      dmem_wren       ,
    output [5:0]    dmem_req_tid    , // request transaction id , ignore it before we implement cache
    output [31:0]               dmem_addr       ,
    output [3:0]                dmem_strb       ,
    output [31:0]               dmem_wdata      ,
    input [31:0]                dmem_rdata      ,
    input                       dmem_ack        , // Cache will give ACK to LSU if cache hit happen
    output                      dmem_flush      , 
    //DDR Access Request Interface
    output                      ddr_req         ,
    output                      ddr_type        ,
    output [5:0]    ddr_req_tid     , // request transaction id , ignore it before we implement cache
    output [31:0]               ddr_addr        ,
    output [31:0]               ddr_wdata       ,
    input  [31:0]               ddr_rdata       ,
    input                       ddr_ack         ,
    input                       ddr_ack_type    ,
    input [5:0]     ddr_ack_tid     ,
    //Device Access Interface
    //waddr ch
    output [5:0]    dev_awtid       ,
    output [31:0]               dev_awaddr      ,
    output [2:0]                dev_awprot      ,
    output                      dev_awvalid     ,
    input                       dev_awready     ,
    //wdata ch 
    output [5:0]    dev_wtid        , 
    output [31:0]               dev_wdata       ,
    output [3:0]                dev_wstrb       ,
    output                      dev_wvalid      ,
    input                       dev_wready      ,
    //b resp ch
    output [5:0]    dev_btid        ,
    input  [1:0]                dev_bresp       ,
    input                       dev_bvalid      ,
    output                      dev_bready      ,
    //raddr ch
    output [5:0]    dev_artid       ,
    output [31:0]               dev_araddr      ,
    output [2:0]                dev_arprot      ,
    output                      dev_arvalid     ,
    input                       dev_arready     ,
    //rdata ch
    output [5:0]    dev_rtid        ,
    input  [31:0]               dev_rdata       ,
    input  [1:0]                dev_rresp       ,
    input                       dev_rvalid      ,
    output                      dev_rready      
);

wire            dmem_hit     ;
wire            dmem_ack_type;



//store queue signals
    //lsu ctrl
    wire                      lsu_store_ready       ;
    wire                      dmem_store_req        ;
    wire [5:0]    dmem_store_req_tid    ;
    wire [31:0]               dmem_store_addr       ;
    wire [31:0]               dmem_store_wdata      ;
    wire                      dmem_store_ack        =dmem_ack_type;
    wire                      dmem_store_hit        =dmem_ack                ;
    wire                      dmem_store_flush      ;
    wire [3-1:0]              dmem_store_info       ;
    //ddr store
    wire                      ddr_store_req         ;
    wire [5:0]    ddr_store_req_tid     ;
    wire [31:0]               ddr_store_addr        ;
    wire [31:0]               ddr_store_wdata       ;
    wire                      ddr_store_ack         =ddr_ack & ddr_ack_type;
    wire [5:0]    ddr_store_ack_tid     =ddr_ack_tid;
    //dev store to do
    wire                      dev_store_req         ;
    wire                      dev_store_addr        ;
    wire [32-1:0]             dev_store_wdata       ;
    //resp
    wire [5:0]    store_resp_inst_id    ;
    wire                      store_resp_vld        ;
    wire                      store_resp_rd_vld     ;
    wire [5:0]                store_resp_rd_ind     ;
    wire [31:0]               store_resp_rd_val     ;
    wire                      store_exp_vld         ;

//load queue signals
    //lsu ctrl
    wire                      lsu_load_ready       ;

    wire                      dmem_load_req        ;
    wire [5:0]    dmem_load_req_tid    ;
    wire [31:0]               dmem_load_addr       ;
    wire [31:0]               dmem_load_rdata     =dmem_rdata;
    wire                      dmem_load_ack       =dmem_ack & (~dmem_ack_type); 
    // wire                      dmem_load_hit       =dmem_hit                   ;
    wire                      dmem_load_flush      ; 
    wire [3-1:0]              dmem_load_info       ;

    //DDR read
    wire                      ddr_load_req         ;
    wire [5:0]    ddr_load_req_tid     ; 
    wire [31:0]               ddr_load_addr        ;
    wire [31:0]               ddr_load_rdata      =ddr_rdata  ;
    wire                      ddr_load_ack        =ddr_ack & (~ddr_ack_type)   ;
    wire [5:0]    ddr_load_ack_tid    =ddr_ack_tid;
    //dev read      to assign
    wire                      dev_load_req         ;
    wire [31:0]               dev_load_rdata       ; //to assign
    //resp
    wire [5:0]  load_resp_inst_id   ;
    wire                    load_resp_vld       ;
    wire                    load_resp_rd_vld    ;
    wire [5:0]              load_resp_rd_ind    ;
    wire [31:0]             load_resp_rd_val    ;
    wire                    load_exp_vld        ;
//load prior store
    //dmem
    wire                      dmem_store_req_o;
    // wire                      dmem_store_req_en=(dmem_load_req & dmem_store_req)| (dmem_load_req & dmem_store_req_o);
    wire                      dmem_store_req_en=1'b1;
    wire                      dmem_store_req_in=(dmem_load_req & dmem_store_req)| (dmem_load_req & dmem_store_req_o);
    dffr #(.DW(1))                 dmem_store_req_ff(clk,rst_n,dmem_store_req_en,dmem_store_req_in,dmem_store_req_o);
    //ddr
    wire                      ddr_store_req_o;
    wire                      ddr_store_req_en=1'b1;
    wire                      ddr_store_req_in=(ddr_load_req & ddr_store_req)| (ddr_load_req & ddr_store_req_o);
    dffr #(.DW(1))                 ddr_store_req_ff(clk,rst_n,ddr_store_req_en,ddr_store_req_in,ddr_store_req_o);

//lsu signals
    //DMem Control

    assign                    dmem_req    =dmem_store_req_o | dmem_load_req | dmem_store_req  ;
    assign                    dmem_type   =~dmem_load_req                                     ;   //0: load ,1: store
    assign                    dmem_wren   =dmem_req & dmem_type                               ;
    assign                    dmem_req_tid=dmem_load_req? dmem_load_req_tid:dmem_store_req_tid;
    assign                    dmem_addr   =dmem_load_req? dmem_load_addr   :dmem_store_addr   ;
    assign                    dmem_flush  =dmem_load_req? dmem_store_flush :dmem_load_flush   ;


    wire [31:0]     mem_wdata_byte;
    wire [31:0]     mem_wdata_half;
    wire [31:0]     mem_wdata_word;
    wire [3:0]      byte_strb;
    wire [3:0]      half_strb;
    wire [3:0]      word_strb;
    wire [3-1:0]              dmem_info   =dmem_load_req? dmem_load_info  :dmem_store_info    ;
    assign                    byte_strb      = {4{dmem_addr[1:0] == 2'b00}} & 4'b0001 |
                                               {4{dmem_addr[1:0] == 2'b01}} & 4'b0010 |
                                               {4{dmem_addr[1:0] == 2'b10}} & 4'b0100 |
                                               {4{dmem_addr[1:0] == 2'b11}} & 4'b1000 ;
    assign                    half_strb      = {4{dmem_addr[1:0] == 2'b00}} & 4'b0011 |
                                               {4{dmem_addr[1:0] == 2'b10}} & 4'b1100 ;
    assign                    word_strb      = 4'b1111;
    assign                    dmem_strb      = {4{dmem_info[1:0]==2}} & byte_strb |        // byte
                                               {4{dmem_info[1:0]==1}} & half_strb |        // half
                                               {4{dmem_info[1:0]==0}} & word_strb ;        // word

    assign                    mem_wdata_byte = {32{dmem_addr[1:0] == 2'b00}} & {24'b0,dmem_store_wdata[7:0]} |
                                               {32{dmem_addr[1:0] == 2'b01}} & {16'b0,dmem_store_wdata[7:0],8'b0} |
                                               {32{dmem_addr[1:0] == 2'b10}} & {8'b0,dmem_store_wdata[7:0],16'b0} |
                                               {32{dmem_addr[1:0] == 2'b11}} & {dmem_store_wdata[7:0],24'b0} ;
    assign                    mem_wdata_half = {32{dmem_addr[1:0] == 2'b00}} & {16'b0,dmem_store_wdata[15:0]} |
                                               {32{dmem_addr[1:0] == 2'b10}} & {dmem_store_wdata[15:0],16'b0} ;
    assign                    mem_wdata_word = dmem_store_wdata;
    assign                    dmem_wdata     = {32{dmem_info[1:0]==2}} & mem_wdata_byte |
                                               {32{dmem_info[1:0]==1}} & mem_wdata_half |
                                               {32{dmem_info[1:0]==0}} & mem_wdata_word ;
    // assign                       dmem_wdata  =dmem_store_wdata;
    //DDR Access Request Interface
    assign                    ddr_req    =ddr_store_req_o | ddr_load_req  | ddr_store_req     ;
    assign                    ddr_type   =ddr_load_req? 0:1                                   ;
    assign                    ddr_req_tid=ddr_load_req? ddr_load_req_tid:ddr_store_req_tid    ;
    assign                    ddr_addr   =ddr_load_req? ddr_load_addr   :ddr_store_addr       ;
    assign                    ddr_wdata  =ddr_store_wdata                                     ;
    //lsu ctrl
    assign                    lsu_ready  =lsu_store_ready & lsu_load_ready                    ;
    //
    wire                         retire_vld;
    assign                       retire_vld      =lsu_stor_retire;

    //resp
    assign                   lsu_resp_inst_id=load_resp_vld ? load_resp_inst_id:
                                              store_resp_vld? store_resp_inst_id:0;
    assign                   lsu_resp_vld    =store_resp_vld | load_resp_vld;
    assign                   lsu_resp_rd_vld =load_resp_vld ? load_resp_rd_vld:
                                              store_resp_vld? store_resp_rd_vld:0;;
    assign                   lsu_resp_rd_ind =load_resp_vld ? load_resp_rd_ind:
                                              store_resp_vld? store_resp_rd_ind:0;;
    assign                   lsu_resp_rd_val =load_resp_vld ? load_resp_rd_val:
                                              store_resp_vld? store_resp_rd_val:0;;
    assign                   lsu_exp_vld     =load_resp_vld ? load_exp_vld:
                                              store_resp_vld? store_exp_vld:0;;


//RAW 
    wire RAW_flag;
    wire [32-1:0] RAW_load_data;

    dffr #(.DW(1))                 dmem_type_ff (clk,rst_n,1'b1,dmem_type,dmem_ack_type);


    frv_store_queue inst_frv_store_queue
        (
            .clk                (clk),
            .clk_en             (clk_en),
            .rst_n              (rst_n),

            .RAW_load_data      (RAW_load_data),
            .RAW_flag           (RAW_flag),

            .lsu_req            (lsu_req),
            .lsu_ctrl_unsign    (lsu_ctrl_unsign),
            .lsu_ctrl_load      (lsu_ctrl_load),
            .lsu_ctrl_store     (lsu_ctrl_store),
            .lsu_ctrl_word      (lsu_ctrl_word),
            .lsu_ctrl_half      (lsu_ctrl_half),
            .lsu_ctrl_byte      (lsu_ctrl_byte),
            .lsu_inst_id        (lsu_inst_id),
            .lsu_flush          (lsu_flush),
            .lsu_flush_id       (lsu_flush_id),
            .lsu_load_ready     (lsu_load_ready),
            .lsu_store_ready    (lsu_store_ready),

            .retire_vld         (retire_vld),
            .lsu_op1_val        (lsu_op1_val),
            .lsu_op2_val        (lsu_op2_val),
            .lsu_store_data     (lsu_store_data),
            .dmem_store_req     (dmem_store_req),
            .dmem_store_req_tid (dmem_store_req_tid),
            .dmem_store_addr    (dmem_store_addr),
            .dmem_store_wdata   (dmem_store_wdata),
            .dmem_store_ack     (dmem_store_ack),
            .dmem_store_hit     (dmem_store_hit),
            .dmem_store_flush   (dmem_store_flush),
            .dmem_store_info    (dmem_store_info),

            .ddr_store_req      (ddr_store_req),
            .ddr_store_req_tid  (ddr_store_req_tid),
            .ddr_store_addr     (ddr_store_addr),
            .ddr_store_wdata    (ddr_store_wdata),
            .ddr_store_ack      (ddr_store_ack),
            .ddr_store_ack_tid  (ddr_store_ack_tid),
            
            .store_resp_inst_id (store_resp_inst_id)    ,
            .store_resp_vld     (store_resp_vld)        ,
            .store_resp_rd_vld  (store_resp_rd_vld)     ,
            .store_resp_rd_ind  (store_resp_rd_ind)     ,
            .store_resp_rd_val  (store_resp_rd_val)     ,
            .store_exp_vld      (store_exp_vld)         ,
            .load_resp_vld      (load_resp_vld)         ,
            // .dev_awtid       (dev_awtid),
            .dev_awaddr      (dev_awaddr),
            .dev_awprot      (dev_awprot),
            .dev_awvalid     (dev_awvalid),
            .dev_awready     (dev_awready),
            //wdata ch 
            // .dev_wtid        (dev_wtid), 
            .dev_wdata       (dev_wdata),
            .dev_wstrb       (dev_wstrb),
            .dev_wvalid      (dev_wvalid),
            .dev_wready      (dev_wready),
            //b resp ch
            // .dev_btid        (dev_btid),
            .dev_bresp       (dev_bresp),
            .dev_bvalid      (dev_bvalid),
            .dev_bready      (dev_bready)
        

        );

    frv_load_queue inst_frv_load_queue
        (
            .clk               (clk),
            .pd_rst            (pd_rst),
            .rst_n             (rst_n),
            
            .lsu_req           (lsu_req),
            .lsu_ctrl_unsign   (lsu_ctrl_unsign),
            .lsu_ctrl_load     (lsu_ctrl_load),
            .lsu_ctrl_store    (lsu_ctrl_store),
            .lsu_ctrl_word     (lsu_ctrl_word),
            .lsu_ctrl_half     (lsu_ctrl_half),
            .lsu_ctrl_byte     (lsu_ctrl_byte),
            .lsu_inst_id       (lsu_inst_id),
            .RAW_flag          (RAW_flag),
            .RAW_data          (RAW_load_data),
            .lsu_flush         (lsu_flush),
            .lsu_flush_id      (lsu_flush_id),
            .lsu_op1_val       (lsu_op1_val),
            .lsu_op2_val       (lsu_op2_val),
            .lsu_resp_inst_id  (load_resp_inst_id),
            .lsu_resp_vld      (load_resp_vld),
            .lsu_resp_rd_vld   (load_resp_rd_vld),
            .lsu_resp_rd_ind   (load_resp_rd_ind),
            .lsu_resp_rd_val   (load_resp_rd_val),
            .lsu_exp_vld       (load_exp_vld),
            .lsu_store_ready   (lsu_store_ready),
            .lsu_load_ready    (lsu_load_ready),
            .dmem_load_req     (dmem_load_req),
            .dmem_load_req_tid (dmem_load_req_tid),
            .dmem_load_addr    (dmem_load_addr),
            .dmem_load_rdata   (dmem_load_rdata),
            .dmem_load_ack     (dmem_load_ack),
            .dmem_load_flush   (dmem_load_flush),
            .dmem_load_info    (dmem_load_info),

            .ddr_load_req      (ddr_load_req),
            .ddr_load_req_tid  (ddr_load_req_tid),
            .ddr_load_addr     (ddr_load_addr),
            .ddr_load_rdata    (ddr_load_rdata),
            .ddr_load_ack      (ddr_load_ack),
            .ddr_load_ack_tid  (ddr_load_ack_tid),

            // .dev_artid          (dev_artid),
            .dev_araddr         (dev_araddr),
            // .dev_arprot         (dev_arprot),
            .dev_arvalid        (dev_arvalid),
            .dev_arready        (dev_arready),

            // .dev_rtid           (dev_rtid),
            .dev_rdata          (dev_rdata),
            .dev_rresp          (dev_rresp),
            .dev_rvalid         (dev_rvalid),
            .dev_rready         (dev_rready)
        );


endmodule


